package com.pactera.madp.cp.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.XmlUtil;
import com.pactera.madp.cp.config.EsbSocketClientConfig;
import lombok.extern.slf4j.Slf4j;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.w3c.dom.Document;

import java.io.*;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.text.DecimalFormat;
import java.util.Date;

@Slf4j
@Service
public class EsbSocketService {

    private static EsbSocketClientConfig esbSocketClientConfig;

    @Autowired
    public void setEsbSocketClientConfig(EsbSocketClientConfig esbSocketClientConfig) {
        EsbSocketService.esbSocketClientConfig = esbSocketClientConfig;
    }

    public String send(String openid) throws Exception {
        String req = createReq(openid);
        log.info("请求报文实体:{}", req);
        Socket socket = null;
        DataInputStream input = null;
        DataOutputStream out = null;
        String info = null;
        try {
            socket = new Socket();
            socket.setSoTimeout(esbSocketClientConfig.getReqTimeout());
            socket.connect(new InetSocketAddress(esbSocketClientConfig.getHost(), esbSocketClientConfig.getPort()),esbSocketClientConfig.getConnectTimeout());

            input = new DataInputStream(socket.getInputStream());
            out = new DataOutputStream(socket.getOutputStream());
            out.write(req.getBytes("UTF-8"));
            out.flush();
            socket.shutdownOutput();

            byte[] headBytes = new byte[8];
            int off;
            for (off = 0; off < 8;) {
                off += input.read(headBytes, off, 8 - off);
                if (off < 0) {
                    throw new Exception("读取报文头错误");
                }
            }
            int size = new DecimalFormat().parse(new String(headBytes)).intValue();
            log.info("响应报文长度:{}", size);

            if (size > (20 * 1024 * 1024)) {
                throw new Exception("报文体大小超过20M");
            }
            int len = 0;
            int off1 = 0;
            byte[] bytes = new byte[size];
            while (off1 < size) {
                len = input.read(bytes, off1, size - off1);
                if (-1 == len) {
                    break;
                }
                off1 += len;
            }
            if (size != off1) {
                throw new Exception("读取报文体错误");
            }
            info = new String(bytes, "UTF-8");
            log.info("响应报文实体:{}", info);
        } catch (Exception e) {
            log.error("发送请求报文失败", e);
        } finally {
            close(input, out, socket);
        }
        return info;
    }

    private void close(DataInputStream input, DataOutputStream out, Socket socket) throws Exception {
        if (input != null) {
            input.close();
        }
        if (out != null) {
            out.close();
        }
        if (socket != null) {
            socket.close();
        }
    }

    public String createReq(String openid) {
        //创建document对象
        org.dom4j.Document document = DocumentHelper.createDocument();
        //设置编码
        document.setXMLEncoding("UTF-8");
        //创建根节点service
        Element service = document.addElement("service");
        //在service节点加入子节点SYS_HEAD
        Element SYS_HEAD = service.addElement("SYS_HEAD");
        handleSYS_HEAD(SYS_HEAD);
        //在service节点加入子节点BODY
        Element BODY = service.addElement("BODY");
        handleBODY(BODY, openid);

        //将document对象转换成字符串
        String xml = document.asXML();
        xml = xml + System.getProperty("line.separator");
        Integer size = xml.getBytes().length;
        log.info("报文长度:{}", size);
        xml = String.format("%08d", Integer.valueOf(size)) + xml;
        log.info("生成请求报文实体:{}", xml);
        return xml;
    }

    public String getCoreCstNo(String rsp) {
        Document document = XmlUtil.parseXml(rsp);
        org.w3c.dom.Element service = XmlUtil.getRootElement(document);
        org.w3c.dom.Element BODY = XmlUtil.getElement(service, "BODY");
        org.w3c.dom.Element CoreCstNo = XmlUtil.getElement(BODY, "CoreCstNo");
        String coreCstNo = CoreCstNo.getTextContent();
        return coreCstNo;
    }

    public void handleSYS_HEAD(Element SYS_HEAD) {
        Date now = DateUtil.date();
        String date = DateUtil.format(now, "yyyyMMdd");
        String time = DateUtil.format(now, "HHmmss");
        SYS_HEAD.addElement("ServiceCode").setText(esbSocketClientConfig.getServiceCode());
        SYS_HEAD.addElement("ServiceScene").setText(esbSocketClientConfig.getServiceScene());
        SYS_HEAD.addElement("ConsumerId").setText(esbSocketClientConfig.getConsumerId());
        SYS_HEAD.addElement("ConsumerSeqNo").setText(date + time);
        SYS_HEAD.addElement("TranDate").setText(date);
        SYS_HEAD.addElement("TranTime").setText(time);
    }

    public void handleBODY(Element BODY, String openid) {
        BODY.addElement("WeChatId").setText(openid);
    }

}
